//constants
var WID = 100;
var HEI = 100;
var ADDHEI = 25;
var ROUND = 10;
var ROUND_MULTI = 30;
var OFFSET = 15;
var SMALLOFFSET = 10;
var SCALE = 0.95;
var MAX_MUL_WIDTH = 350;
var PICSIZE = 70;
var PICSIZE_MULTI = 80;
var ORG_OFFSET_WID = 50;
var ORG_OFFSET_HEI = 40;
var ORG_SPACE_WID = 50;
var ORG_SPACE_HEI = 50;

function element() {
	this.g; 
	this.svg = sampleSVG;
	
	this.x;
	this.y;
	this.width;
	this.height;

	this.Draw = function(x, y) {
		this.g = sampleSVG.append("g");
		this.CreateObject(this.g);  	
		this.g.attr("transform", "translate("+x+","+y+")");
	}

	this.Picture = function(d)
	{
		this.picture = d;
		return this;
	}

	this.Amount = function(d)
	{
		this.amount = d;
		return this;
	}
} 

function timer(time) {
	this.inheritFrom = element;
	this.inheritFrom();

	this.time = time;
	this.timeMsSec = time * 60 * 1000;
	this.leftMsSec = time * 60 * 1000 +1;
	this.past = new Date();
	this.running = false;
	
	this.picture = "clock.png";

	this.__defineGetter__("height",function(){
		return HEI+ADDHEI;
	});

	this.__defineGetter__("width",function(){
		return HEI;
	});

	this.Draw = function(x, y) {
		this.g = sampleSVG.append("g");
		this.CreateObject(this.g);  	
		this.g.attr("transform", "translate("+x+","+y+")");

		this.g.on("click", changeRunning);
		this.g.on("mousemove", checkColorCoding);

		var thisRef = this;

		function changeRunning()
		{
			if(d3.event.button == 0)
			{
				thisRef.running = !thisRef.running; 
				thisRef.timText.attr("fill", !thisRef.running?"gray":"red");
			}
			else
			{
				thisRef.leftMsSec = thisRef.timeMsSec-1;
			}
		}

		function checkColorCoding()
		{
			thisRef.hoverRect.style("fill", !thisRef.running?"blue":"red");
		}
	}

	this.CreateObject = function(o)
	{		  
		o.append("image")
		.attr("x", 0)
		.attr("y", 0)
		.attr("width", HEI)
		.attr("height", HEI)  
		.attr("xlink:href", this.picture)

		var rad = 0.6 * HEI/2;

		var w = 100,
		h = 100,
		x = d3.scale.ordinal().domain(d3.range(3)).rangePoints([0, w], 2);

		o.append("rect")
		.attr("x", 0)
		.attr("y", HEI)
		.attr("rx", ROUND)
		.attr("ry", ROUND)
		.attr("width", WID)
		.attr("height", ADDHEI)  
		.attr("class", "basic");

		this.timText = o.append("text")
		.attr("x", WID/2)
		.attr("y", HEI + 17)
		.attr("fill", "gray")
		.attr("font-family", "sans-serif")
		.attr("text-anchor", "middle")

		var fields = [
		              {name: "hour", value: 0, size: 4, rad:20, inrad: 0},
		              {name: "minutes", value: 0, size: 60, rad:30, inrad: 0},
		              {name: "seconds", value: 0, size: 60, rad:30, inrad: 29}
		              ];

		var past = this.past;
		var now = this.past;
		var timeMsSec = this.timeMsSec;
		var thisRef = this;

		var arc = d3.svg.arc()
		.innerRadius(function(d) {return d.inrad})
		.outerRadius(function(d) {return d.rad})
		.startAngle(0)
		.endAngle(function(d) { return (d.value / d.size) * 2 * Math.PI; });

		setInterval(intervalStep, 100);
		intervalStep();

		this.hoverRect = o.append("rect")
		.attr("x", 0)
		.attr("y", 0)
		.attr("rx", ROUND)
		.attr("ry", ROUND)
		.attr("width", WID)
		.attr("height", HEI)  
		.attr("class", "timerHover");

		function arcTween(b) {
			var i = d3.interpolate({value: b.previous}, b);
			return function(t) {
				return arc(i(t));
			};
		}

		function intervalStep() {
			now = new Date();

			if(thisRef.running == true)
			{
				thisRef.leftMsSec -= now.getTime() - past.getTime();
			}
			past = now;

			var left = thisRef.leftMsSec;

			if (left < 0)
			{ 
				left = 0;
				thisRef.running = false;
				thisRef.leftMsSec = thisRef.timeMsSec;
				thisRef.timText.text("Time Over!");
				alert("TIME IS OVER!!!");
				return
			}

			var leftHour = Math.floor(left / (1000*60*60));
			var leftMin = Math.floor(left / (1000*60)) % -60;
			var leftSec = Math.floor(left/1000) % -60;


			fields[0].previous = fields[0].value; fields[0].value = Math.ceil(leftHour, 4);
			fields[1].previous = fields[1].value; fields[1].value = leftMin;
			fields[2].previous = fields[2].value; fields[2].value = leftHour > 0 ? 0 : leftSec;


			var myTxt = (leftSec<10?("0"+leftSec):leftSec)
			myTxt =(leftMin<10?("0"+leftMin):leftMin) + ":" + myTxt;
			myTxt =(leftHour<10?("0"+leftHour):leftHour) + ":" + myTxt;

			thisRef.timText.text(myTxt);

			var path = o.selectAll("path")
			.data(fields.filter(function(d) { return d.value; }), function(d) { return d.name; });

			path.enter().append("svg:path")
			.attr("transform", function(d, i) { return "translate("+HEI/2+","+(5+HEI/2)+ ")"; })
			.transition()
			.ease("elastic")
			.duration(750)
			.attrTween("d", arcTween);

			path.transition()
			.ease("elastic")
			.duration(750)
			.attrTween("d", arcTween);

			path.exit().transition()
			.ease("bounce")
			.duration(750)
			.attrTween("d", arcTween)
			.remove();

		}

	}
}


function simple(name) {
	this.inheritFrom = element;
	this.inheritFrom();

	this.name = name;
	this.amount = "";
	this.picture = "";
	this.g;

	this.__defineGetter__("height",function(){
		if(this.amount != "") 
			return HEI + ADDHEI;
		else
			return HEI;
	});

	this.__defineGetter__("width",function(){
		return WID;
	});
	
	this.CreateObject = function(o)
	{		  
		//console.log(this.name + " > " + this.width + ","+ this.height + "\n");
		o.append("rect")
		.attr("x", 0)
		.attr("y", 0)
		.attr("rx", ROUND*2)
		.attr("ry", ROUND)
		.attr("width", WID)
		.attr("height", HEI)  
		.attr("class", "simple")

		if(this.picture != "")
		{
			o.append("image")
			.attr("x", (HEI-PICSIZE)/2)
			.attr("y", 3)
			.attr("width", PICSIZE)
			.attr("height", PICSIZE)  
			.attr("xlink:href", this.picture)
			.attr("class", "simple")
		}

		if(this.amount != "")
		{
			o.append("rect")
			.attr("x", 0)
			.attr("y", HEI)
			.attr("rx", ROUND)
			.attr("ry", ROUND)
			.attr("width", WID)
			.attr("height", ADDHEI)  
			.attr("class", "basic")

			o.append("text")
			.attr("x", WID/2)
			.attr("y", HEI + 17)
			.attr("fill", "gray")
			.attr("font-family", "sans-serif")
			.attr("text-anchor", "middle")
			.text(this.amount)
		}

		o.append("text")
		.attr("x", WID / 2)
		.attr("y", HEI - 10)
		.attr("font-family", "sans-serif")
		.attr("text-anchor", "middle")
		.text(this.name)  
	}
} 

function multi(name) {
	this.inheritFrom = element;
	this.inheritFrom();

	this.name = name;
	this.amount = "";
	this.picture = "";
	this.g;

	this.__defineGetter__("height",function(){
		this.RecalcElements();
		return this.intHeight;
	});

	this.__defineGetter__("width",function(){
		this.RecalcElements();
		return this.intWidth;
	});
	
	this.intHeight = HEI;
	this.intWidth = WID;
	
	this.innerWidth;
	this.innerHeight;
	this.picOffset = 0;

	this.dict = new Array();
	this.subElement = [];

	this.Add = function(element)
	{
		this.subElement.push(element);

		this.RecalcElements();

		return this;
	}
 
	this.RecalcElements = function()
	{
		var tmpWid = 0, tmpHei = 0;
		var maxWid = 0, maxHei = 0;
		var tmpDict = new Array();

		if(this.subElement.length == 0)
		{
			return;
		}
		
		for ( var int = 0; int < this.subElement.length; int++) {
			var subEl = this.subElement[int];

			var elHei = subEl.height;
			var elWid = subEl.width;

			tmpDict[int] = tmpWid + "," + maxHei;

			tmpHei = Math.max(tmpHei, elHei);


			if(tmpWid + elWid > MAX_MUL_WIDTH)
			{
				maxHei += tmpHei + SMALLOFFSET;
				tmpWid = 0;
				tmpHei = 0;
				tmpDict[int] = tmpWid + "," + maxHei;
				tmpHei = Math.max(tmpHei, elHei);
			}

			tmpWid += elWid;						
			tmpWid += SMALLOFFSET;

			maxWid = Math.max(tmpWid, maxWid);
		}

		maxHei += tmpHei;

		this.dict = tmpDict;
		this.innerWidth = maxWid;
		this.innerHeight = maxHei;	

		this.intWidth = this.innerWidth * SCALE + 2* OFFSET;
		this.intHeight = this.innerHeight * SCALE + 2 * OFFSET + ADDHEI;

		if(this.picture != "")
		{
			this.picOffset = PICSIZE_MULTI + OFFSET; 
			this.intWidth += this.picOffset ;
		}
		else
		{
			this.picOffset = 0;
		}

		//console.log(this.name + " new width/height: "+this.width+","+this.height+"\n");			    

	}


	this.CreateObject = function(o)
	{
		this.RecalcElements();
		//console.log(this.name + " > " + this.width + ","+ this.height + "\n");

		o.append("rect")
		.attr("x", 0)
		.attr("y", 0)
		.attr("rx", ROUND_MULTI)
		.attr("ry", ROUND_MULTI)
		.attr("width", this.width)
		.attr("height", this.height)  
		.attr("class", "multi")

		if(this.picture != "")
		{
			o.append("image")
			.attr("x", OFFSET)
			.attr("y", (this.height-PICSIZE_MULTI)/2)
			.attr("width", PICSIZE_MULTI)
			.attr("height", PICSIZE_MULTI)  
			.attr("xlink:href", this.picture)
		}

		o.append("text")
		.attr("x", this.width / 2)
		.attr("y", this.height - 10)
		.attr("font-family", "sans-serif")
		.attr("text-anchor", "middle")
		.text(this.name)  

		var subElementsGroup = o.append("g").attr("transform", 
				"translate("+(OFFSET+(this.picture!="" ? this.picOffset : 0))+","+OFFSET+") scale("+SCALE+") ");

		for ( var int = 0; int < this.subElement.length; int++) {
			var subEl = this.subElement[int];
			var subG = subElementsGroup.append("g").
			attr("transform", 
					"translate(" + this.dict[int]  + ")");

			subEl.CreateObject(subG);
		}
	}
} 

function organizeMaster()
{
	this.organizeRefs = new Array();
	this.connections = new Array();
	this.dictRef = new Array();
	this.groups = new Array();

	this.maxGroup = 0;
	this.maxPos = 0;
	
	this.posGrid = new Array();
	this.posHei = new Array();
	this.maxHei = new Array();
	this.maxWid = 0;

	this.intCnt = 0;

	this.Add = function(el, group, pos, lnkGroup, lnkPos)
	{
		if(group == undefined && pos == undefined)
		{
			group = 0;
			pos = this.intCnt++;
		}

		if(el == undefined)
			return this;

		var tmpOrg = new organizeRef(el, group, pos);

		this.organizeRefs.push(tmpOrg);

		if (this.dictRef[group] == undefined)
			this.dictRef[group] = new Array();

		this.dictRef[group][pos] = tmpOrg;

		if(lnkGroup != undefined && lnkPos != undefined)
		{
			this.connections.push([group, pos, lnkGroup, lnkPos]);
		}

		return this;
	}

	this.ConnectEl = function(elPre, el)
	{
		var topX = elPre.x+elPre.width/2;
		var topY = elPre.y+elPre.height;

		var bottomX = el.x+el.width/2;
		var bottomY = el.y;


		var values = [
		              [topX, topY],
		              [topX, bottomY-ORG_OFFSET_HEI/2],
		              [bottomX, bottomY-ORG_OFFSET_HEI/2],
		              [bottomX, bottomY]
		              ]
		;

		var line = d3.svg.line()
		.x(function(d) { return d[0]; })
		.y(function(d) { return d[1]; })
		.interpolate("basis");


		sampleSVG.selectAll(".line")
		.data([values], function(d){return d;})
		.enter()
		.append("path")
		.attr("class", "line")
		.attr("d", line);
	}

	this.CalcSupportValues = function()
	{

		// calc height and width array to look up positioning of elements
		for ( var i = 0; i < this.organizeRefs.length; i++) 
		{
			var el = this.organizeRefs[i];
			if(this.groups[el.group] == undefined)
				this.groups[el.group] = new Array();

			//this.groups[el.group].push(el);
			this.groups[el.group][el.pos] = el;
			
			if (this.maxHei[el.pos] == undefined)
				this.maxHei[el.pos] = 0;
			this.maxHei[el.pos] = Math.max(this.maxHei[el.pos], el.elRef.height);	
			
			this.maxGroup = Math.max(this.maxGroup, el.group);
			this.maxPos = Math.max(this.maxPos, el.pos);
		}	

		var tmpHeiSum = 0; 
		for ( var i = 0; i < this.maxHei.length; i++) {
			if( this.maxHei[i] == undefined )
				this.maxHei[i] = ORG_SPACE_HEI;

			this.posHei[i] = tmpHeiSum;
			tmpHeiSum += this.maxHei[i] + ORG_OFFSET_HEI;
		}
		
		for ( var i = 0; i <= this.maxPos; i++) {
			var tmpX = 0;
			var tmpSumX = 0;
			
			if(this.posGrid[i] == undefined)
				this.posGrid[i] = new Array();
			
			for ( var j = 0; j <= this.maxGroup; j++) {
				this.posGrid[i][j] = tmpSumX;
				
				if(this.dictRef[j] != undefined && this.dictRef[j][i] != undefined)
				{
					tmpX = this.dictRef[j][i].elRef.width + ORG_OFFSET_WID;
				}
				else
				{
					tmpX = 5;
				}
				tmpSumX += tmpX;
			}
			this.posGrid[i][this.maxGroup+1] = tmpSumX;
			this.maxWid = Math.max(this.maxWid, tmpSumX);
		}
		console.log(this.posGrid);
		
		// Calculate position and assign to elRef - do features like Center here...
		for ( var i = 0; i < this.organizeRefs.length; i++) 
		{
			var el = this.organizeRefs[i];

			el.x = this.posGrid[el.pos][el.group];
			el.y = this.posHei[el.pos] + (this.maxHei[el.pos]-el.height)/2;	// center the image within the max range
		}
	}
	
	this.DrawBG = function()
	{
		var layers0 = new Array();
		var n = 1, // number of layers
	    	m = 200; // number of samples per layer

		for ( var i = 0; i <= this.maxGroup; i++) {
			var tmpArray = new Array();
			
			var tmpObj = new Object();
			tmpObj.x =  this.posHei[0] - ORG_SPACE_HEI;
			tmpObj.y0 = - ORG_SPACE_WID/2;
			tmpObj.y1 = - ORG_SPACE_WID/2;
			tmpArray.push(tmpObj);
			
			for ( var j = 0; j <= this.maxPos; j++) {
				var tmpObj = new Object();
				tmpObj.x =  this.posHei[j];
				tmpObj.y0 = this.posGrid[j][i]- ORG_SPACE_WID/2;
				tmpObj.y1 = this.posGrid[j][i+1] - ORG_SPACE_WID/2;
				tmpArray.push(tmpObj);
				
				var tmpObj1 = new Object();
				tmpObj1.x =  this.posHei[j] + (this.maxHei[j])/2;
				tmpObj1.y0 = this.posGrid[j][i]- ORG_SPACE_WID/2;
				tmpObj1.y1 = this.posGrid[j][i+1] - ORG_SPACE_WID/2;
				tmpArray.push(tmpObj1);
				
				var tmpObj2 = new Object();
				tmpObj2.x =  this.posHei[j] + (this.maxHei[j]);
				tmpObj2.y0 = this.posGrid[j][i]- ORG_SPACE_WID/2;
				tmpObj2.y1 = this.posGrid[j][i+1] - ORG_SPACE_WID/2;
				tmpArray.push(tmpObj2);
			}
			
			var tmpObj2 = new Object();
			tmpObj2.x =  this.posHei[this.maxPos] + (this.maxHei[this.maxPos]) + ORG_SPACE_HEI;
			tmpObj2.y0 = - ORG_SPACE_WID/2;
			tmpObj2.y1 = - ORG_SPACE_WID/2;
			tmpArray.push(tmpObj2);		
			
			layers0.push(tmpArray);
		}

		var color = d3.scale.category10();
	
		var area = d3.svg.area()
		    .x(function(d) { console.log(d); return d.x; })
		    .y0(function(d) { return d.y0; })
		    .y1(function(d) { return d.y1; })
			.interpolate("basis");
		
		var bg = sampleSVG.append("g");
		bg.attr("transform", "rotate(90) scale(1,-1) translate(0,5)");
		
			bg.selectAll("path")
		    .data(layers0)
		  .enter().append("path")
		    .attr("d", area)
		    .attr("class", "bg_swimm")
		    .style("fill", function(d,i) { return color(Math.random()); });
	}
	
		
	this.DrawAll = function()
	{
		// Calculates Grid to position elements
		this.CalcSupportValues();

		// Draw Background
		this.DrawBG();

		// Connect lines within one group
		for ( var i = 0; i < this.groups.length; i++) {
			var groupTmp = this.groups[i];
			for ( var j = 1; j < groupTmp.length; j++) {
				var groupElPre = groupTmp[j-1];
				var groupEl = groupTmp[j];
				
				if(groupElPre == undefined || groupEl == undefined)
				{
					continue;
				}
				
				this.ConnectEl(groupElPre, groupEl);
			}
		}

		// Connect additionally entered connections
		for ( var int = 0; int < this.connections.length; int++) {
			var con = this.connections[int];
			var firstEl = this.dictRef[con[0]][con[1]];
			var secEl   = this.dictRef[con[2]][con[3]];

			if(firstEl != undefined && secEl != undefined)
			{
				this.ConnectEl(firstEl, secEl);
			}
		}
		
		// FINALLY! draw these elements
		
		for ( var i = 0; i < this.organizeRefs.length; i++) 
		{
			var el = this.organizeRefs[i];
			var tmp = el.elRef;
			
			tmp.Draw(el.x, el.y);
		}
		
		// Adjust width, so image can be centered ;)
		svg.attr("width", this.maxWid + ORG_SPACE_WID);
		svg.attr("height",this.posHei[this.maxPos] + (this.maxHei[this.maxPos]) + ORG_SPACE_HEI);
		sampleSVG.attr("transform", "translate("+ORG_SPACE_WID/2+","+ORG_SPACE_HEI/2+")")

	}
}

function organizeRef(el, group, pos)
{
	this.pos = pos + 0;
	this.group = group;
	this.elRef = el;	

	this.width = el.width;
	this.height = el.height;
	this.x = undefined;
	this.y = undefined;
}


